
想的到會用到的套件都差不多裝完了,最後來提升一點閱讀體驗,自從某次加班一段時間過勞產生了肘隧道症候群後,除了換直立滑鼠,調整坐姿,買夠高的椅子以外,也讓自己習慣75%的鍵盤(100%的鍵盤太大,會卡住滑鼠移動,造成正常坐姿下左右不平衡),也開始越來越習慣盡量用純鍵盤的方式寫程式和爬文,所以今天來添加一點鍵盤操作吧。
把鍵盤事件註冊的核心邏輯抽出來做成 Composable ,然後根據頁面或元件的需要,獨立為每個頁面或元件做按鍵事件宣告。
type Key = string;
type KeyCombination = string;
interface KeyBoardControlConfig {
    [key: string]: () => void
}
const keyStrategies: { [key in Key]: () => void } = {};
const combinationStrategies: { [key in KeyCombination]: () => void } = {};
function keyDownHandler(event: KeyboardEvent, showKey: boolean) {
    const key = event.key;
    if (key in keyStrategies) {
        keyStrategies[key]();
    }
    const combination = `${event.ctrlKey ? 'Ctrl+' : ''}${event.shiftKey ? 'Shift+' : ''}${event.altKey ? 'Alt+' : ''}${key}`;
    if (combination in combinationStrategies) {
        combinationStrategies[combination]();
    }
    if (showKey) {
        console.log('key:', key);
        console.log('combination:', combination);
    }
}
export default (config: KeyBoardControlConfig, showKey: boolean) => {
    for (const key in config) {
        if (key.includes('+')) {
            combinationStrategies[key] = config[key];
        } else if (key.length === 1) {
            keyStrategies[key] = config[key];
        }
        // } else {
        //     codeStrategies[key] = config[key];
        // }
    }
    onMounted(() => {
        window.addEventListener('keydown', event => keyDownHandler(event, showKey));
    });
    onBeforeUnmount(() => {
        window.removeEventListener('keydown', event => keyDownHandler(event, showKey));
    });
};
showKey 這個參數是拿來決定是否在按鍵時 console key name 的,只是為了 Debug 方便,完全是可以不用加沒關係。
在 docs/.vitepress/theme/layout/expandLayout.vue 中註冊事件。
<script setup lang="ts">
    import DefaultTheme from 'vitepress/theme';
    import { useData, useRouter } from 'vitepress';
    import useKeyBoardControl from '@hooks/useKeyBoardControl'; // [!code ++]
    function selectorClickHandler(selector: string) { // [!code ++]
        const element = document.querySelector(selector) as HTMLElement; // [!code ++]
        if (element) { // [!code ++]
            element.click(); // [!code ++]
        } // [!code ++]
    } // [!code ++]
    function getOutlines() { // [!code ++]
        const outlines = document.querySelectorAll('.VPDocOutlineItem.root .outline-link'); // [!code ++]
        const activeIndex = Array.from(outlines).findIndex(outline => outline.classList.contains('active')); // [!code ++]
        return { // [!code ++]
            outlines, // [!code ++]
            activeIndex // [!code ++]
        }; // [!code ++]
    } // [!code ++]
    useKeyBoardControl({ // [!code ++]
        'ArrowLeft': () => { // [!code ++]
            selectorClickHandler('.pager-link.prev'); // [!code ++]
        }, // [!code ++]
        'ArrowRight': () => { // [!code ++]
            selectorClickHandler('.pager-link.next'); // [!code ++]
        }, // [!code ++]
        'Ctrl+ArrowUp': () => { // [!code ++]
            const { outlines, activeIndex } = getOutlines(); // [!code ++]
            if (outlines.length <= 0) // [!code ++]
                return; // [!code ++]
            if (activeIndex > 0) { // [!code ++]
                const prevIndex = activeIndex - 1; // [!code ++]
                if (prevIndex >= 0) { // [!code ++]
                    (outlines[prevIndex] as HTMLElement).click(); // [!code ++]
                } // [!code ++]
            } else { // [!code ++]
                window.scrollTo(0, 0); // 頁面卷軸到最上面 // [!code ++]
            } // [!code ++]
        }, // [!code ++]
        'Ctrl+ArrowDown': () => { // [!code ++]
            const { outlines, activeIndex } = getOutlines(); // [!code ++]
            if (outlines.length > 0) { // [!code ++]
                const nextIndex = activeIndex + 1; // [!code ++]
                if (nextIndex < outlines.length) { // [!code ++]
                    (outlines[nextIndex] as HTMLElement).click(); // [!code ++]
                } // [!code ++]
            } // [!code ++]
        } // [!code ++]
    }, true); // [!code ++]
</script>
看程式碼可以發現,我們註冊了四個事件
短時間內也想不到還有什麼事件需要增加的了。
不過在移動目錄的時候,會發現他是直接跳過去的,使用體驗有點差,我們在 docs/.vitepress/theme/scss/basic.scss 裡面添加:
html {
    scroll-behavior: smooth;
}
這樣他就會滑順的移動過去囉~
實際效果可以到 Opshell 的部落格 看看幹話文章,嘗試看看喔~